package com.disruptor.demo.handler;

import com.disruptor.demo.event.SeckillOrderEvent;
import com.lmax.disruptor.EventHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 订单处理处理器：Disruptor消费链的第二步处理器
 * 依赖关系：必须在StockCheckHandler（库存校验）处理完成后执行
 * 核心职责：
 * 1. 处理库存校验通过的订单（如模拟订单入库、生成订单快照等）
 * 2. 对前序步骤失败的订单直接跳过，避免无效处理
 * 3. 通过批量日志减少IO开销，同时保留关键统计数据
 */
@Slf4j
@Component
public class OrderProcessHandler implements EventHandler<SeckillOrderEvent> {
    /**
     * 累计成功处理的订单数
     * 原子类保证线程安全：Disruptor消费者线程可能单线程执行，但用AtomicInteger确保计数准确性（兼容未来多线程消费场景）
     */
    private final AtomicInteger processedCount = new AtomicInteger(0);

    /**
     * 当前批次处理的订单数
     * 用于批量日志计数，达到阈值后打印汇总日志，减少单条日志的IO开销
     */
    private final AtomicInteger batchProcessCount = new AtomicInteger(0);

    /**
     * 批量日志阈值：每处理1000条订单或达到事件批次末尾时，打印一次汇总日志
     * 阈值设计：平衡日志颗粒度与性能（阈值过小→日志过多，阈值过大→监控延迟）
     */
    private static final int BATCH_LOG_THRESHOLD = 2000;

    /**
     * Disruptor事件处理核心方法：接收并处理订单事件
     * 调用时机：当RingBuffer中有新事件，且前序处理器（StockCheckHandler）完成后触发
     *
     * @param event      待处理的秒杀订单事件（包含订单信息与前序处理结果）
     * @param sequence   事件在RingBuffer中的唯一序列号（用于追踪事件位置）
     * @param endOfBatch 是否为当前批次的最后一个事件（用于触发批次末尾的汇总日志）
     */
    @Override
    public void onEvent(SeckillOrderEvent event, long sequence, boolean endOfBatch) throws Exception {
        // 1. 前序步骤失败检查：若库存校验失败（errorMsg非空），直接跳过处理
        // 设计目的：避免对已确认失败的订单做无效处理，节省资源
        if (event.getErrorMsg() != null) {
            log.debug("【订单处理】跳过失败订单：orderId={}，原因：{}", event.getOrderId(), event.getErrorMsg());
            return;
        }

        // 2. 更新事件处理状态：标记为"ORDER_PROCESS"，用于追踪事件流转阶段
        event.setProcessStatus("ORDER_PROCESS");
        String orderId = event.getOrderId();

        try {
            // --------------------------
            // 生产环境核心业务逻辑（此处简化为示意）：
            // 1. 订单信息持久化（如写入MySQL订单表，建议用批量插入优化性能）
            // 2. 生成订单快照（缓存到Redis，供用户查询）
            // 3. 记录订单操作日志（异步写入Kafka，用于审计）
            // --------------------------

            // 3. 订单处理成功：更新计数器
            processedCount.incrementAndGet(); // 累计成功数+1
            batchProcessCount.incrementAndGet(); // 批次计数+1

            // 4. 批量打印汇总日志：达到阈值或批次末尾时触发
            // 结合endOfBatch的目的：确保最后一批未达阈值的事件也能打印日志
//            if (batchProcessCount.get() >= BATCH_LOG_THRESHOLD || endOfBatch) {
//                log.info("【订单处理批次汇总】本批次处理：{}条，累计处理成功：{}条",
//                        batchProcessCount.get(), processedCount.get());
//                batchProcessCount.set(0); // 重置批次计数
//            }
            if (batchProcessCount.get() >= BATCH_LOG_THRESHOLD) {
                log.info("【订单处理批次汇总】本批次处理：{}条，累计处理成功：{}条",
                        batchProcessCount.get(), processedCount.get());
                batchProcessCount.set(0); // 重置批次计数
            }

        } catch (Exception e) {
            // 5. 处理异常：记录错误信息，供后续通知处理器使用
            // 区别：此处为系统异常（如数据库连接失败），而非业务失败（业务失败在前序步骤已处理）
            event.setErrorMsg("订单处理失败：" + e.getMessage());
            log.error("【订单处理异常】orderId={}，原因：{}", orderId, e.getMessage(), e);
        }
    }

}
